home *** CD-ROM | disk | FTP | other *** search
- /*
- * $Id: jpeg.c,v 0.91 1994/02/20 00:52:49 zhao Pre-Release $
- *
- *. This file is part of BIT shareware package. After the two weeks of
- * free evaluation period, you are encouraged (required) to register
- * your copy for a small registration fee, which is $35 for personal use
- * and $50 for commercial, government and institutional use.
- *
- * Copyright(c) 1993, 1994 by T.C. Zhao.
- * All rights reserved.
- *
- * Permission to use, copy, and distribute this software in its entirety
- * for non-commercial purposes is hereby granted, provided that the
- * above shareware and copyright notices and this permission notice
- * appear in all copies and their documentation.
- *
- * This software may be modified for your own use, but modified versions
- * may not be distributed without prior consent of the author.
- *
- * This software is provided "as is" without expressed or implied
- * warranty of any kind.
- *
- *.
- *
- * JPEG(JFIF) related routines are based in part on the work of
- * the Independent JPEG Group. Also uses the Independent JPEG Group's
- * library. See related files in jpeg directory for more details.
- */
- #ifndef NO_JPEG
-
- #if !defined(lint) && defined(F_ID)
- char *id_jpg = "$Id: jpeg.c,v 0.91 1994/02/20 00:52:49 zhao Pre-Release $";
- #endif
-
- #include "bit.h"
- #include <stdlib.h> /* exit prototype */
- #include "jinclude.h"
-
- /* const may or may not be defined to be empty by jinclude.h */
- #ifdef Const
- #undef const
- #endif
-
- #include <setjmp.h>
-
-
- /******** Decompression parameters: always output RGB *************/
-
- static int jpg_quant = 0; /* set to # of colors */
- static int jpg_blksm = 0; /* block smoothing */
-
- /******* compression parameters: all used **************************/
-
- static int jpeg_qval = 75; /* default Q-value */
- static int jpeg_sval = 0; /* default smoothing factor */
- static int jpeg_opt = 0; /* optimize */
-
- /******** some bit control parameters *********************************/
-
- static int sofar, isjwrite; /* line read and io id */
- static jmp_buf jpg_jmp; /* error recoveraty jump buffer */
- static IPTR jpg_current; /* local copy of image pointer */
- static long jpg_rlines; /* reporting control */
-
- static int read_JPEG_file(FILE *);
- static int write_JPEG_file(FILE *);
-
- /*******************************************************************
- * One liner summary of JPEG output options
- ******************************************************************/
-
- /* ARGSUSED */
- const char *
- JPEG1_wdefault(const IPTR ip)
- {
- static char rep[30];
- sprintf(rep, "Q=%d Smooth=%d", jpeg_qval, jpeg_sval);
- return rep;
- }
-
- /*****************************************************************
- * Solicit output options
- ****************************************************************/
-
- /* ARGSUSED */
- int
- JPEG1dump_init(IPTR im)
- {
- (void) get2int("Q value", &jpeg_qval, 5, 100,
- "Smooth", &jpeg_sval, 0, 100,
- "Optimize", &jpeg_opt, HELP_JPEG, 0);
- return 0;
- }
-
- /*********************************************************************
- * The entry point for writing
- *********************************************************************/
- int
- JPEG1_dump(IPTR img)
- {
- sofar = 0;
- jpg_current = img;
- isjwrite = 1;
- return write_JPEG_file(img->fp);
- }
-
- /*
- * the use of the canned library sort of breaks down the systematic approach
- * of the BIT program as both the BIT program and the library want to take
- * control. Have to fake description because we do not want to know too many
- * details of the file format, the consequence of this is that the loading
- * routine will have to do the memoery allocation explicitly.
- */
-
- int
- JPEG1_desc(IPTR im)
- {
- /* fake the size to 1X1 to signal info reporting func */
- jpg_current = im;
- jpg_current->w = 1;
- jpg_current->h = 1;
- jpg_current->esize = 4;
- jpg_current->type = T_RGBA;
- return 0;
- }
-
- int
- JPEG1_load(IPTR im)
- {
-
- if (jpg_current != im)
- {
- Bark("JpegLoad", "Internal error");
- return -1;
- }
-
- isjwrite = sofar = 0;
-
- if (read_JPEG_file(im->fp) < 0)
- return -1;
- if (im->type != T_GRAY)
- im->type = T_RGBA;
- return sofar;
- }
-
- static external_methods_ptr emethods;
- METHODDEF void
- trace_message(const char *msgtext)
- {
- /*
- * error messages may have in it the file name, which could be
- * MAXDLEN+MAXFLEN long. Really wish there were something line an
- * snprintf
- */
- char errmsg[MAXFLEN + MAXDLEN], *p;
- const char *func = isjwrite ? "JPG_write" : "JPG_read";
-
- /* wish there were an snprintf */
- sprintf(errmsg, msgtext,
- emethods->message_parm[0], emethods->message_parm[1],
- emethods->message_parm[2], emethods->message_parm[3],
- emethods->message_parm[4], emethods->message_parm[5],
- emethods->message_parm[6], emethods->message_parm[7]);
-
- /* break long lines (otherwise clipped by GL) */
- if (strlen(errmsg) < 40)
- {
- Bark(func, "%s:%s", jpg_current->ifile, errmsg);
- }
- else
- { /* break it at space */
- if ((p = strchr(errmsg + 15, ' ')))
- *p = '\n';
- Bark(func, "%s:%s", jpg_current->ifile, errmsg);
- }
- }
-
- /* really do not what to exit, rather transfer control to main driver */
- METHODDEF void
- error_exit(const char *msgtext)
- {
- trace_message(msgtext); /* report the error message */
- (*emethods->free_all) (); /* clean up memory allocation & temp files */
- longjmp(jpg_jmp, 1); /* return control to outer routine */
-
- }
-
- METHODDEF void
- output_init(decompress_info_ptr info)
- {
- jpg_current->w = info->image_width;
- jpg_current->h = info->image_height;
-
- jpg_rlines = progress_report("Loading JPEG ...", jpg_current->h);
- if (info->out_color_space == CS_GRAYSCALE)
- jpg_current->type = T_GRAY;
- else if (info->out_color_space == CS_RGB)
- jpg_current->type = T_RGBA;
- else
- { /* unecessary unless the driver screwed-up */
- Bark("JPG_load", "%s: Bad Colorspace", jpg_current->ifile);
- }
-
- /* always converts to RGB by load */
- update_image_info(jpg_current);
- if (img_get_rastermem(jpg_current) < 0)
- longjmp(jpg_jmp, 1);
- }
-
- METHODDEF void
- put_pixel_rows(decompress_info_ptr info, int num_rows,
- JSAMPIMAGE pixel_data)
- {
- register rgba_t *rgba;
- register JSAMPROW ptr0, ptr1, ptr2, ptr;
- register int row;
- register int width = info->image_width;
- register int height = info->image_height;
-
- #ifdef V4A
- /*
- * it would appear that V4a's code might produce more scanlines than they
- * are. Check here
- */
-
- if ((num_rows + sofar) > height)
- {
- num_rows = height - sofar;
- M_warn("OutputRows", "sofar=%d height=%d num_rows=%d\n",
- sofar, height, num_rows);
- }
- #endif
-
- if (info->out_color_space == CS_RGB)
- {
- for (row = 0; row < num_rows; row++, sofar++)
- {
- rgba = ((rgba_t **) jpg_current->mraster)[height - 1 - sofar];
- ptr0 = pixel_data[0][row];
- ptr1 = pixel_data[1][row];
- ptr2 = pixel_data[2][row];
- ptr = ptr0 + width;
- for (; ptr0 < ptr; ptr0++, ptr1++, ptr2++)
- {
- *rgba++ = Pack(*ptr0, *ptr1, *ptr2);
- }
- REPORT(sofar, jpg_rlines);
- }
- }
- else if (info->out_color_space == CS_GRAYSCALE)
- {
- for (row = 0; row < num_rows; row++, sofar++)
- {
- rgba = ((rgba_t **) jpg_current->mraster)[height - 1 - sofar];
- ptr0 = ptr = pixel_data[0][row];
- for (ptr = ptr0 + width; ptr0 < ptr; ptr0++)
- {
- *rgba++ = Pack(*ptr0, *ptr0, *ptr0);
- }
- REPORT(sofar, jpg_rlines);
- }
- }
-
- }
-
- /*
- * color map is ready assigned in put_color_map
- */
- /* ARGSUSED */
- METHODDEF void
- put_cmap_rows(decompress_info_ptr info, int num_rows,
- JSAMPIMAGE pixel_data)
- {
- register rgba_t *rgba, *rs, *mrgb = jpg_current->cmap->p_h.rgba;
- register JSAMPROW ptr;
- register int row;
- register int width = jpg_current->w, height = jpg_current->h;
-
- for (row = 0; row < num_rows; row++, sofar++)
- {
- ptr = pixel_data[0][row];
- rgba = ((rgba_t **) jpg_current->mraster)[height - 1 - sofar];
- for (rs = rgba + width; rgba < rs;)
- {
- *rgba++ = mrgb[*ptr++];
- }
- REPORT(sofar, jpg_rlines);
- }
- }
-
- METHODDEF void
- put_color_map(decompress_info_ptr info, int num_colors,
- JSAMPARRAY cm)
- {
- int i, j;
-
- jpg_current->type = T_CMAP;
- jpg_current->cmap->colors = num_colors;
- for (j = 0; j < info->color_out_comps; j++)
- {
- for (i = 0; i < num_colors; i++)
- {
- jpg_current->cmap->ct[j][i] = cm[j][i];
- }
- }
-
- info->methods->put_pixel_rows = put_cmap_rows;;
- if (info->color_out_comps == 1)
- { /* grap scale */
- for (i = 0; i < num_colors; i++)
- jpg_current->cmap->p_h.rgba[i] = Pack(cm[0][i], cm[0][i], cm[0][i]);
- jpg_current->cmap->packed = 1;
- }
- else if (info->color_out_comps == 3)
- {
- pack_cmap(jpg_current->cmap);
- }
- else
- {
- Bark("JPG_load", "%s: BadColorComponent", jpg_current->ifile);
- longjmp(jpg_jmp, 1);
- }
- }
-
- /* ARGSUSED */
- METHODDEF void
- output_term(decompress_info_ptr info)
- {
- remove_progress_report();
- }
-
-
- METHODDEF void
- d_ui_method_selection(decompress_info_ptr info)
- {
- if (info->jpeg_color_space == CS_GRAYSCALE)
- info->out_color_space = CS_GRAYSCALE;
- info->methods->output_init = output_init;
- info->methods->put_color_map = put_color_map;
- info->methods->put_pixel_rows = put_pixel_rows;
- info->methods->output_term = output_term;
- }
-
- static int
- read_JPEG_file(FILE * fp)
- {
-
- static struct Decompress_info_struct dcinfo;
- static struct Decompress_methods_struct dc_methods;
- static struct External_methods_struct e_methods;
-
- dcinfo.input_file = fp;
- dcinfo.output_file = NULL; /* if no actual output file involved */
-
- dcinfo.methods = &dc_methods; /* links to method structs */
- dcinfo.emethods = &e_methods;
- emethods = &e_methods; /* save struct addr for possible access */
-
- e_methods.trace_message = trace_message;
- e_methods.error_exit = error_exit; /* supply error-exit routine */
-
- e_methods.trace_level = 0;
- e_methods.num_warnings = 0;
- e_methods.first_warning_level = 0;
- e_methods.more_warning_level = 3;
-
- if (setjmp(jpg_jmp))
- {
- remove_progress_report();
- return sofar;
- }
- jselmemmgr(&e_methods); /* select std memory allocation routines */
-
- dc_methods.d_ui_method_selection = d_ui_method_selection;
- dcinfo.desired_number_of_colors = jpg_quant;
-
- /* quantize only if sensible number of color is requested */
- dcinfo.quantize_colors = jpg_quant > 10;
-
- dcinfo.do_block_smoothing = jpg_blksm;
- j_d_defaults(&dcinfo, TRUE);
- jselrjfif(&dcinfo);
-
-
- #ifdef MTRACE
- M_trace("ReadJpeg", "Right before decompress");
- #endif
- jpeg_decompress(&dcinfo);
- return sofar;
- }
-
- /*
- * compressing routines
- */
- METHODDEF void
- input_init(compress_info_ptr info)
- {
- info->image_width = jpg_current->w;
- info->image_height = jpg_current->h;
- if (jpg_current->type == T_GRAY)
- {
- info->input_components = 1;
- info->in_color_space = CS_GRAYSCALE;
- }
- else
- {
- info->in_color_space = CS_RGB;
- info->input_components = 3;
- }
- info->data_precision = PCBITS; /* bits per pixel component value */
- jpg_rlines = progress_report("Writing JPEG ...", jpg_current->h);
- }
-
- METHODDEF void
- get_input_row(compress_info_ptr info, JSAMPARRAY pixel_row)
- {
- register JSAMPROW ptr0, ptr1, ptr2;
- register int col, r, g, b;
- register rgba_t *rgba, *rend;
-
- rgba = ((rgba_t **) jpg_current->mraster)[jpg_current->h - 1 - sofar];
- if (jpg_current->type == T_RGBA)
- {
- ptr0 = pixel_row[0];
- ptr1 = pixel_row[1];
- ptr2 = pixel_row[2];
- for (rend = rgba + info->image_width; rgba < rend; rgba++)
- {
- Unpack(*rgba, r, g, b);
- *ptr0++ = (JSAMPLE) r;
- *ptr1++ = (JSAMPLE) g;
- *ptr2++ = (JSAMPLE) b;
- }
- REPORT(sofar, jpg_rlines);
- sofar++;
- }
- else if (jpg_current->type == T_GRAY)
- {
- ptr0 = pixel_row[0];
- for (col = 0; col < info->image_width; col++)
- {
- r = (*rgba & 0xff);
- *ptr0++ = (JSAMPLE) r;
- rgba++;
- }
- REPORT(sofar, jpg_rlines);
- sofar++;
- }
- }
-
- /* ARGSUSED */
- METHODDEF void
- input_term(compress_info_ptr info)
- {
- remove_progress_report();
- }
-
- METHODDEF void
- c_ui_method_selection(compress_info_ptr info)
- {
- if (info->in_color_space == CS_GRAYSCALE)
- j_monochrome_default(info);
- jselwjfif(info);
- }
-
- static int
- write_JPEG_file(FILE * fp)
- {
- static struct Compress_info_struct cinfo;
- static struct Compress_methods_struct c_methods;
- static struct External_methods_struct e_methods;
-
- cinfo.emethods = &e_methods;
- cinfo.methods = &c_methods; /* links to method structs */
- emethods = &e_methods; /* save struct addr for possible access */
- e_methods.error_exit = error_exit; /* supply error-exit routine */
- e_methods.trace_message = trace_message;
- jselmemmgr(&e_methods); /* select std memory allocation routines */
- c_methods.input_init = input_init;
-
- if (setjmp(jpg_jmp))
- {
- remove_progress_report();
- fclose(cinfo.output_file);
- return sofar;
- }
-
- c_methods.get_input_row = get_input_row;
- c_methods.input_term = input_term;
- c_methods.c_ui_method_selection = c_ui_method_selection;
- cinfo.input_file = NULL; /* if no actual input file involved */
- cinfo.output_file = fp;
-
- /* permitted compression options */
- j_c_defaults(&cinfo, jpeg_qval, FALSE);
- cinfo.smoothing_factor = jpeg_sval;
- cinfo.optimize_coding = jpeg_opt;
-
- #ifdef MTRACE
- M_trace("ReadJpeg", "Right before compress");
- #endif
- jpeg_compress(&cinfo);
- fflush(cinfo.output_file);
- return sofar;
- }
-
- #endif
-